package cn.itcast.mq.spring;

import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.time.LocalTime;
import java.util.Map;

/**
 * 监听队列 -> 消费者
 */
@Component
public class SpringRabbitListener {

    // 监听的队列, 会自动将监听到的消息 赋值给参数 message
    @RabbitListener(queues = {"simple.queue", "simple.queue2"})
    public void listenSimpleQueueMessage(String massage) {
        System.out.println("spring 消费者收到消息: " + massage);
    }

    /**
     * WorkQueue 模型:
     *
     * 基本思路如下：
     * 在publisher服务中定义测试方法，每秒产生50条消息，发送到simple.queue
     * 在consumer服务中定义两个消息监听者，都监听simple.queue队列
     * 消费者1每秒处理50条消息，消费者2每秒处理10条消息
     */
    // 监听的队列, 会自动将监听到的消息 赋值给参数 message
    @RabbitListener(queues = {"work.queue"})
    public void listenWorkQueueOne(String massage) throws InterruptedException {
        System.out.println("spring 消费者1 收到消息: " + massage + " -> " + LocalTime.now());
        // 休眠 20, 生产者一样, 使得 1s 消费 50 条消息
        Thread.sleep(20);
    }

    @RabbitListener(queues = {"work.queue"})
    public void listenWorkQueueTow(String massage) throws InterruptedException {
        System.err.println("spring 消费者2 收到消息: " + massage + " -> " + LocalTime.now());
        // 使得 1s 消费 5 条消息
        Thread.sleep(200);
    }


    /**
     * 利用SpringAMQP演示FanoutExchange的使用
     *
     * 实现思路如下：
     * 在consumer服务中，利用代码声明队列、交换机，并将两者绑定
     * 在consumer服务中，编写两个消费者方法，分别监听fanout.queue1和fanout.queue2
     * 在publisher中编写测试方法，向 my.fanout 发送消息
     */
    @RabbitListener(queues = {"fanout.queue1"})
    public void listenFanoutQueueOne(String massage) throws InterruptedException {
        System.out.println("spring 消费者收到 fanout.queue1 的消息: " + massage + " -> " + LocalTime.now());
        // 休眠 20, 生产者一样, 使得 1s 消费 50 条消息
        Thread.sleep(20);
    }

    @RabbitListener(queues = {"fanout.queue2"})
    public void listenFanoutQueueTwo(String massage) throws InterruptedException {
        System.out.println("spring 消费者收到 fanout.queue2 的消息: " + massage + " -> " + LocalTime.now());
        // 休眠 20, 生产者一样, 使得 1s 消费 50 条消息
        Thread.sleep(20);
    }


    /**
     * 发布订阅-DirectExchange:
     *
     * Direct Exchange 会将接收到的消息根据规则路由到指定的Queue，因此称为路由模式（routes）。
     * 每一个Queue都与Exchange设置一个BindingKey
     * 发布者发送消息时，指定消息的RoutingKey
     * Exchange将消息路由到BindingKey与消息RoutingKey一致的队列
     *
     *  利用SpringAMQP演示DirectExchange的使用:
     *      实现思路如下：
     *      利用@RabbitListener声明Exchange、Queue、RoutingKey
     *      在consumer服务中，编写两个消费者方法，分别监听direct.queue1和direct.queue2
     *      在publisher中编写测试方法，向 my.direct 发送消息
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue1"), // 默认就是 direct
            exchange = @Exchange(name = "my.direct", type = ExchangeTypes.DIRECT),
            key = {"red", "blue"}
    ))
    public void listenDirectQueueOne(String massage) {
        System.out.println("spring 消费者收到 direct.queue1 的消息: " + massage + " -> " + LocalTime.now());
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue2"),
            exchange = @Exchange(name = "my.direct", type = ExchangeTypes.DIRECT),
            key = {"red", "yellow"}
    ))
    public void listenDirectQueueTwo(String massage) {
        System.out.println("spring 消费者收到 direct.queue2 的消息: " + massage + " -> " + LocalTime.now());
    }


    /**
     *  发布订阅-TopicExchange:
     *
     *   TopicExchange与DirectExchange类似，区别在于routingKey必须是多个单词的列表，并且以 . 分割。 如: chain.news
     *   Queue与Exchange指定BindingKey时可以使用通配符：
     *   #：代指0个或多个单词   ->  chain.# ,  #.news
     *   *：代指一个单词       ->  china.* ,  *.news
     *
     *   利用SpringAMQP演示TopicExchange的使用:
     *   实现思路如下：
     *   并利用@RabbitListener声明Exchange、Queue、RoutingKey
     *   在consumer服务中，编写两个消费者方法，分别监听topic.queue1和topic.queue2
     *   在publisher中编写测试方法，向 my.topic 发送消息
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue1"), // 默认就是 direct
            exchange = @Exchange(name = "my.topic", type = ExchangeTypes.TOPIC),
            key = "china.#"
    ))
    public void listenTopicQueueOne(String massage) {
        System.out.println("spring 消费者收到 topic.queue1 的消息: " + massage + " -> " + LocalTime.now());
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue2"),
            exchange = @Exchange(name = "my.topic", type = ExchangeTypes.TOPIC),
            key = "#.news"
    ))
    public void listenTopicQueueTwo(String massage) {
        System.out.println("spring 消费者收到 topic.queue2 的消息: " + massage + " -> " + LocalTime.now());
    }


    /**
     *  消息转换器
     */
    @RabbitListener(queues = "object.queue")
    public void listenObjectQueue(Map<String, Object> msg) {
        System.out.println("spring 消费者收到 object.queue 的消息: " + msg);
    }

}
